package com.gsi.webstore.platform.storefront.pipelet;

import com.intershop.beehive.core.capi.pipeline.Pipelet;
import com.intershop.beehive.core.capi.pipeline.PipelineDictionary;
import com.gsi.webstore.platform.adapter.storelocator.internal.client.data.Distance;
import com.gsi.webstore.platform.adapter.storelocator.internal.client.data.GeoPoint;
import com.gsi.webstore.platform.adapter.storelocator.internal.client.data.LatLngBounds;
import com.gsi.webstore.platform.adapter.storelocator.internal.client.data.StoreConfigurationDetail;
import com.gsi.webstore.platform.adapter.storelocator.internal.client.data.UnitMeasure;
import com.gsi.webstore.platform.adapter.storelocator.internal.util.DistanceCalculator;
import com.intershop.beehive.core.capi.pipeline.PipeletExecutionException;

/**
 * Prepares search data before making the store search call.
 */
public class PrepareInteractiveStorefrontSearchParameters extends Pipelet
{

    /**
     * Constant used to access the pipeline dictionary with key
     * 'StoreConfiguration'
     */
    public static final String DN_STORE_CONFIGURATION = "StoreConfiguration";
    /**
     * Constant used to access the pipeline dictionary with key 'Latitude'
     */
    public static final String DN_LATITUDE = "Latitude";
    /**
     * Constant used to access the pipeline dictionary with key 'Longitude'
     */
    public static final String DN_LONGITUDE = "Longitude";

    /**
     * Constant used to access the pipeline dictionary with key 'NorthLatitude'
     */
    public static final String DN_NORTH_LATITUDE = "NorthLatitude";

    /**
     * Constant used to access the pipeline dictionary with key 'SouthLatitude'
     */
    public static final String DN_SOUTH_LATITUDE = "SouthLatitude";

    /**
     * Constant used to access the pipeline dictionary with key 'EastLongitude'
     */
    public static final String DN_EAST_LONGITUDE = "EastLongitude";

    /**
     * Constant used to access the pipeline dictionary with key 'WestLongitude'
     */
    public static final String DN_WEST_LONGITUDE = "WestLongitude";

    /**
     * Constant used to access the pipeline dictionary with key
     * 'PointOfInterest'
     */
    public static final String DN_POINT_OF_INTEREST = "PointOfInterest";
    
    /**
     * Constant used to indicate errors in search
     */
    public static final String DN_SEARCH_ERROR = "ERROR_IN_SEARCH";
    
    /**
     * Constant used to store error key title
     */
    public static final String DN_SEARCH_ERROR_MESSAGE_KEY = "SEARCH_ERROR_MESSAGE_KEY";
    
    /**
     * Constant used to store error key message
     */
    public static final String DN_SEARCH_ERROR_TITLE_KEY = "SEARCH_ERROR_TITLE_KEY";
    
    /**
     * Invalid address title
     */
    public static final String INVALID_ADDRESS_TITLE = "multichannel.storelocator.invalidAddressTitle";
    
    /**
     * Invalid address message
     */
    public static final String INVALID_ADDRESS_MESSAGE = "multichannel.storelocator.invalidAddressMessage";


    /**
     * The pipelet's execute method is called whenever the pipelets gets
     * executed in the context of a pipeline and a request. The pipeline
     * dictionary valid for the currently executing thread is provided as a
     * parameter.
     * 
     * @param dict
     *            The pipeline dictionary to be used.
     * @throws PipeletExecutionException
     *             Thrown in case of severe errors that make the pipelet execute
     *             impossible (e.g. missing required input data).
     */
    public int execute(PipelineDictionary dict) throws PipeletExecutionException
    {

        // lookup 'longitude' in pipeline dictionary
        Double longitude = (Double)dict.get(DN_LONGITUDE);

        // lookup 'latitude' in pipeline dictionary
        Double latitude = (Double)dict.get(DN_LATITUDE);

        // lookup 'NorthLatitude' in pipeline dictionary
        Double northLatitude = (Double)dict.get(DN_NORTH_LATITUDE);

        // lookup 'SouthLatitude' in pipeline dictionary
        Double southLatitude = (Double)dict.get(DN_SOUTH_LATITUDE);

        // lookup 'EastLongitude' in pipeline dictionary
        Double eastLongitude = (Double)dict.get(DN_EAST_LONGITUDE);

        // lookup 'WestLongitude' in pipeline dictionary
        Double westLongitude = (Double)dict.get(DN_WEST_LONGITUDE);

        // lookup 'StoreConfiguration' in pipeline dictionary
        StoreConfigurationDetail storeConfiguration = (StoreConfigurationDetail)dict.get(DN_STORE_CONFIGURATION);
        if (null == storeConfiguration)
        {
            throw new PipeletExecutionException(
                            "Mandatory input parameter 'StoreConfiguration' not available in pipeline dictionary.");

        }

        GeoPoint centerPoint = null;

        if (latitude != null && longitude != null)
        {
            if (latitude == 0 && longitude == 0)
            {
                dict.put(DN_SEARCH_ERROR, true);
                dict.put(DN_SEARCH_ERROR_TITLE_KEY, INVALID_ADDRESS_TITLE);
                dict.put(DN_SEARCH_ERROR_MESSAGE_KEY, INVALID_ADDRESS_MESSAGE);
                return PIPELET_ERROR;
            }
            else
            {
                centerPoint = new GeoPoint(latitude, longitude);
            }
        }
        else
        {
            centerPoint = determineCenterPoint(new LatLngBounds(new GeoPoint(southLatitude, westLongitude),
                            new GeoPoint(northLatitude, eastLongitude)), storeConfiguration.getUnitMeasure());
        }

        dict.put(DN_POINT_OF_INTEREST, centerPoint);

        return PIPELET_NEXT;
    }

    private GeoPoint determineCenterPoint(LatLngBounds latLngBounds, UnitMeasure unitMeasure)
    {
        Distance midDistance = new Distance(DistanceCalculator.getInstance()
                        .calculate(latLngBounds.getNorthEastPoint(), latLngBounds.getSouthWestPoint(), unitMeasure)
                        .getValue() / 2, unitMeasure);

        return latLngBounds.getSouthWestPoint().northEastPoint(midDistance);

    }
}